package stud.mpgame.network;

import org.apache.mina.core.session.IoSession;

import stud.mpgame.network.util.MessageFilter;
import stud.mpgame.network.util.ResponseMessageDescription;
import stud.mpgame.network.util.ResponseUserObject;

import java.util.Collections;
import java.util.Map;
import java.util.HashMap;
import java.util.Set;
import java.util.HashSet;

/**
 * @author f.pavel91@gmail.com
 * @version 1.0
 */
class MessageDispatcher implements IMessageDispatcher {

    private static final int NUMBER_OF_FILTERS = 4;

    private final Map< MessageFilter, Set< IMessageReceivedListener >> messageReceivedListeners = Collections
            .synchronizedMap(new HashMap<MessageFilter, Set<IMessageReceivedListener>>());

    private final Map< MessageFilter, Set<IMessageSentListener> > messageSentListeners = Collections
            .synchronizedMap(new HashMap< MessageFilter, Set< IMessageSentListener > >());

    public void addMessageReceivedListener(MessageFilter messageFilter, IMessageReceivedListener listener) {
        Set< IMessageReceivedListener > currentListeners = messageReceivedListeners.get(messageFilter);
        if(currentListeners == null) {
            currentListeners = new HashSet< IMessageReceivedListener >();
            messageReceivedListeners.put(messageFilter, currentListeners);
        }
        currentListeners.add(listener);
    }

    public void addMessageSentListener(MessageFilter messageFilter, IMessageSentListener listener) {
        Set< IMessageSentListener > currentListeners = messageSentListeners.get(messageFilter);
        if(currentListeners == null) {
            currentListeners = new HashSet< IMessageSentListener >();
            messageSentListeners.put(messageFilter, currentListeners);
        }
        currentListeners.add(listener);
    }

    public void removeMessageReceivedListener(MessageFilter messageFilter, IMessageReceivedListener listener) {
        messageReceivedListeners.get(messageFilter).remove(listener);
    }

    public void removeMessageSentListener(MessageFilter messageFilter, IMessageSentListener listener) {
        messageSentListeners.get(messageFilter).remove(listener);
    }

    public void notifyMessageReceived(Message message) {
        IoSession session = message.getFirstSession();
        MessageDescription messageDescription = getMessageDescription(message);

        MessageFilter[] messageFilters = new MessageFilter[NUMBER_OF_FILTERS];
        messageFilters[0] = new MessageFilter();
        messageFilters[1] = new MessageFilter(session);
        messageFilters[2] = new MessageFilter(messageDescription);
        messageFilters[3] = new MessageFilter(messageDescription, session);

        for(MessageFilter messageFilter : messageFilters) {
            Set< IMessageReceivedListener > currentListeners = messageReceivedListeners.get(messageFilter);
            if(currentListeners != null) {
                for(IMessageReceivedListener currentListener : currentListeners) {
                    currentListener.messageReceived(message);
                }
            }
        }
    }

    void notifyMessageSent(Message message) {
        IoSession session = message.getFirstSession();
        MessageDescription messageDescription = getMessageDescription(message);

        MessageFilter[] messageFilters = new MessageFilter[NUMBER_OF_FILTERS];
        messageFilters[0] = new MessageFilter();
        messageFilters[1] = new MessageFilter(session);
        messageFilters[2] = new MessageFilter(messageDescription);
        messageFilters[3] = new MessageFilter(messageDescription, session);

        for(MessageFilter messageFilter : messageFilters) {
            Set< IMessageSentListener > currentListeners = messageSentListeners.get(messageFilter);
            if(currentListeners != null) {
                for(IMessageSentListener currentListener : currentListeners) {
                    currentListener.messageSent(message);
                }
            }
        }
    }

    private MessageDescription getMessageDescription(Message message) {
        MessageDescription messageDescription = message.getMessageDescription();
        if(messageDescription.equals(ResponseMessageDescription.getInstance())) {
            //find description of ResponseMessage
            ResponseUserObject responseUserObject = (ResponseUserObject) message.getUserObject(ResponseUserObject.class);
            messageDescription = responseUserObject.getMessageDescription();
        }
        return messageDescription;
    }

}